//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <core.h>
#include <crust.h>
#include <asm.h>

#if defined(_GNUC)

#define DECL_SYS_PROXY_ENTRY()              \
    __asm__(                                \
        ".text;"                            \
        ".align 4;"                         \
        ".globl "C_PREFIX"SysProxyEntry;"   \
        C_PREFIX"SysProxyEntry:"            \
        "stmdb  sp!, {r0 - r3};"            \
        "mov    r1, #0xff;"                 \
        "ldr    pc, [r0, #4];"              \
        "nop;"                              \
    )

DECL_SYS_PROXY_ENTRY();

#endif // defined(_GNUC)

#define SYS_PROXY_MOV_OFFSET    4

EXTERN_C void SysProxyEntry(void);

STATIC DECL_CODEINIT void *NewProxyEntryTable();

EXTERN DECL_CODEINIT bool_t CDECL InitProxyEntryTable()
{
    assert(0 == g_initPageDir[PAGEDIR_INDEX(PROXY_ENTRY_BASE)].uValue);

    PageTabEntry *pPageTab = AllocPageTable();
    if (NULL == pPageTab) return FALSE;

    void *pProxyEntryTable = NewProxyEntryTable();
    if (NULL == pProxyEntryTable) {
        DzFreeKernelPage(pPageTab);
        return FALSE;
    }

    memset(pPageTab, 0, c_uSizeOfPageTab);
    pPageTab[PAGETAB_INDEX(PROXY_ENTRY_BASE)].uValue =
        PHYSADDR(pProxyEntryTable)
        | PAGETABENTRY_AP_RO | PAGETABENTRY_C | PAGETABENTRY_B
        | PAGETABENTRY_TYPE_SMALL;

    g_initPageDir[PAGEDIR_INDEX(PROXY_ENTRY_BASE)].uValue =
        PHYSADDR(pPageTab)
        | PAGEDIRENTRY_TYPE_PAGE | PAGEDIRENTRY_DOMAIN(DOMAIN_USER)
        | PAGEDIRENTRY_BACKWORD;

    FlushCache();
    FlushTlb((virtaddr_t)PROXY_ENTRY_BASE);

    return TRUE;
}

STATIC DECL_CODEINIT void *NewProxyEntryTable()
{
    void *pProxyEntryTable = (char *)DzAllocKernelPage();
    if (NULL == pProxyEntryTable) return NULL;

    char *p = (char *)pProxyEntryTable;
    for (int n = 0; n < PROXY_ENTRY_NUM; n++) {
        memcpy(p, (void *)&SysProxyEntry, PROXY_ENTRY_SIZE);
        p[SYS_PROXY_MOV_OFFSET] = n;
        p += PROXY_ENTRY_SIZE;
    }

    return pProxyEntryTable;
}
